import Axios, {
  type AxiosRequestConfig,
  type CustomParamsSerializer,
  type InternalAxiosRequestConfig,
  type AxiosResponse
} from 'axios'

import { stringify } from 'qs'
import { getToken, TokenHeader } from '@/utils/auth'
import { useTokenStore } from '@/stores/token'
import { refresh } from '@/api/auth'

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  baseURL: import.meta.env.VITE_API_BASE_PATH,
  // 请求超时时间
  timeout: 10000,
  headers: {
    Accept: 'application/json, text/plain, */*',
    'Content-Type': 'application/json',
    'X-Requested-With': 'XMLHttpRequest'
  },
  // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
  paramsSerializer: {
    serialize: stringify as unknown as CustomParamsSerializer
  }
}

const axiosInstance = Axios.create(defaultConfig)
axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
  if (config.url && !config.url.includes('/login') && !config.url.includes('/refresh')) {
    const accessToken = getToken().accessToken
    if (accessToken) {
      config.headers[TokenHeader] = accessToken
    }
  }
  return config
})

axiosInstance.interceptors.response.use(
  (response: AxiosResponse) => {
    return response.data
  },
  async (error) => {
    const { response } = error
    // 处理 401 错误
    if (response && response.status === 401) {
      const tokenStore = useTokenStore()
      try {
        // 获取当前的 refreshToken
        const token = getToken()
        if (token && token.refreshToken) {
          // 刷新 token
          const refreshResult = await refresh(token.refreshToken)
          // 更新本地存储的 token
          tokenStore.updateToken(refreshResult.data)
          // 重新发起原请求
          const originalRequest = error.config
          // 更新请求头中的 token
          originalRequest.headers[TokenHeader] = refreshResult.data.accessToken
          // 重新发送请求
          return axiosInstance(originalRequest)
        }
      } catch (refreshError) {
        // 刷新 token 失败，清除本地 token、跳转到错误页面并抛出错误
        tokenStore.clearToken()
        window.location.href = '/error/401'
        return Promise.reject(refreshError)
      }
    }
    return Promise.reject(error)
  }
)

// 创建一个类型安全的 axios 实例
const typedAxiosInstance = {
  get: <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
    return axiosInstance.get(url, config)
  },
  post: <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
    return axiosInstance.post(url, config?.data, config)
  },

  put: <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
    return axiosInstance.put(url, config?.data, config)
  },
  delete: <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
    return axiosInstance.delete(url, config)
  }
}

export default typedAxiosInstance
